package owg.util.editor2d.operations;

import java.util.Arrays;

import owg.util.data.KryoInstance;
import owg.util.data.KryoInstance.K;
import owg.util.data.Pair;
import owg.util.editor2d.ConstructorParams;
import owg.util.editor2d.Editor2D;
import owg.util.editor2d.entity.Placeable2D;
import owg.util.euclidian.V2D;

public class ConstructorInvoker extends Operation
{
	private ConstructorParams cons;
	private Pair<Placeable2D, ConstructorParams> myObject = null;
	private int createdAtIndex = -1;
	private V2D startPos;
	private boolean clearSelection;
	private boolean appendSelection;
	
	@K private ConstructorInvoker() {}
	
	/**
	 * @param cons The constructor to invoke for instantiating the object 
	 * @param appendSelection  Whether to clear the selection when invoking the constructor
	 * @param clearSelection Whether to append the new object to the selection when invoking the constructor
	 */
	public ConstructorInvoker(ConstructorParams cons, V2D startPos, boolean clearSelection, boolean appendSelection)
	{
		this.cons = cons;
		this.startPos = startPos;
		myObject = null;
		this.clearSelection = clearSelection;
		this.appendSelection = appendSelection;
		//Append to end of list the first time we are applied (-1)
		//Use previous insertion index if we are invoked again(redo)
		createdAtIndex = -1;
	}
	
	@Override
	public void apply(Editor2D w) throws OperationFailedException
	{
		try {
			Object[] params = cons.params;
			Object[] clonedParams = new Object[params.length];
			for(int i = 0; i<params.length; i++)
			{
				if(i == cons.instanceListIndex)
					clonedParams[i] = w.instanceList;
				else if(i == cons.posIndex)
					clonedParams[i] = startPos.clone();
				else if(params[i] == null || params[i] instanceof Number || params[i] instanceof Enum || params[i] instanceof Boolean || params[i] instanceof String)
					clonedParams[i] = params[i];
				else if(params[i] instanceof float[])
					clonedParams[i] = KryoInstance.kryo.copy(params[i]);//Come on.
			}
			Object o = cons.constructor().newInstance(clonedParams);
			if(o instanceof Placeable2D)
				myObject = new Pair<Placeable2D,ConstructorParams>((Placeable2D)o, cons);
			else
				throw new IllegalArgumentException("The created object is not a Placeable2D: "+o);
			myObject.a.setName(w.getUniqueName(myObject.a, myObject.a.getDefaultName()));
			createdAtIndex = w.objectCreated(myObject, clearSelection, appendSelection, createdAtIndex);
		}
		catch (Exception err) 
		{
			System.err.println(cons.declaringType.toString());
			System.err.println(Arrays.toString(cons.paramTypes));
			System.err.println(Arrays.toString(cons.params));
			System.err.println("With "+w.instanceList+" at "+cons.instanceListIndex+" and "+startPos+" at "+cons.posIndex);
			throw new OperationFailedException(err);
		}
	}
	@Override
	public String toString()
	{
		return getClass().getSimpleName()+": "+cons+" at "+createdAtIndex;
	}
	
	/**Returns the object created by this constructor(null if not completed yet), and, optionally, erases the object reference from this object.*/
	public Pair<Placeable2D, ConstructorParams> getCreatedObject(boolean erase)
	{
		Pair<Placeable2D, ConstructorParams> val = myObject;
		if(erase)
			myObject = null;
		return val;
	}
}